package crontab

import (
	"fmt"
	"os/exec"
	"reflect"
	"runtime"
	"server/global"
	CustomerModel "server/model/customer"
	customerRes "server/model/customer/response"
	LicenseModel "server/model/license"
	licenseRes "server/model/license/response"
	"server/utils"
	"strings"
	"time"
)

type customerInfo struct {
	name       string
	expireDate time.Time
	saleName   string
}

// sendEmail 发送维保状态的邮件(此方法只用于发送维保信息给售后和商务)
func sendEmail(emailBody string) {
	if emailBody != "" {
		tip := "<span style='color: red'>如有客户新签维保，辛苦及时更新到&nbsp;&nbsp;<a style='text-decoration: none' href='https://drawer.bs58i.baishancdnx.com/#/customer/list'>蜂巢客户管理系统</a>&nbsp;。</span>"
		emailBody += tip
		// 将维保信息发送给系统收件人以及销售leader(销售leader会同步给对应的销售)
		systemRec := strings.Split(global.TD27_CONFIG.SMTP.Rec, ",")
		saleRec := strings.Split(global.TD27_CONFIG.SMTP.SaleRec, ",")
		recipients := append(systemRec, saleRec...)
		err := utils.SendEmail("蜂巢售后相关指标告警", emailBody, recipients)
		if err != nil {
			global.TD27_LOG.Error(fmt.Sprintf("蜂巢售后相关指标告警邮件发送失败，error: %s", err))
		} else {
			global.TD27_LOG.Info("蜂巢售后相关指标告警邮件发送成功.")
		}
	}
}

// UpdateServiceStatus 更新维保状态
func UpdateServiceStatus() {
	global.TD27_LOG.Info("定时任务 【更新维保状态】 开始执行.")
	var expiredCustomer []customerInfo
	// 查询所有在维保期内的客户记录
	var customers []CustomerModel.CustomerModel
	if err := global.TD27_DB.Where("service_status = ?", 1).Preload("Business").Find(&customers).Error; err != nil {
		msg := fmt.Sprintf("查询数据失败: %s", err)
		global.TD27_LOG.Error(msg)
		return
	}

	// 检查&更新记录的 ServiceStatus 字段
	for _, customer := range customers {
		// 检查 ServiceEndDate 是否比今天小
		if customer.ServiceEndDate.Before(time.Now().Local()) {
			c := customerInfo{
				name:       customer.Name,
				expireDate: customer.ServiceEndDate,
				saleName:   customer.Business.Name,
			}
			expiredCustomer = append(expiredCustomer, c)
			customer.ServiceStatus = 2
			if err := global.TD27_DB.Save(&customer).Error; err != nil {
				global.TD27_LOG.Error(fmt.Sprintf("更新数据失败: ID=%d, error: %s", customer.ID, err))
			} else {
				global.TD27_LOG.Info(fmt.Sprintf("客户: %s 维保已更新为过期状态.", customer.Name))
			}
		}
	}

	// 检查是否有新的维保过期的客户
	if len(expiredCustomer) != 0 {
		var emailBody string
		var msg []string
		for _, c := range expiredCustomer {
			m := fmt.Sprintf("客户: %s,&nbsp;&nbsp;&nbsp;&nbsp;维保截止日期: %s,&nbsp;&nbsp;&nbsp;&nbsp;销售: %s", c.name, c.expireDate.Format("2006-01-02"), c.saleName)
			msg = append(msg, m)
		}
		emailBody = fmt.Sprintf("最新维保过期的客户列表：</br>%s</br></br></br>", strings.Join(msg, "</br>"))
		global.TD27_LOG.Info(emailBody)
		sendEmail(emailBody)
	}

	global.TD27_LOG.Info("定时任务 【更新维保状态】 执行完成.")
}

// checkServiceStatus 检查一个月内即将到期的维保客户和过期不足三个月的客户
func checkServiceStatus() {
	var expiresWithinAMonth []customerInfo
	global.TD27_LOG.Info("定时任务 【检查维保状态】 开始执行.")
	// 查询所有在维保期内的客户记录
	var customers []CustomerModel.CustomerModel
	if err := global.TD27_DB.Where("service_status = ?", 1).Preload("Business").Find(&customers).Error; err != nil {
		msg := fmt.Sprintf("查询数据失败: %s", err)
		global.TD27_LOG.Error(msg)
		return
	}

	// 检查&更新记录的 ServiceStatus 字段
	for _, customer := range customers {
		// 检查 ServiceEndDate 是否比当前日期只大一个月以内
		oneMonthFromNow := time.Now().Local().AddDate(0, 1, 0)
		if customer.ServiceEndDate.After(time.Now().Local()) && customer.ServiceEndDate.Before(oneMonthFromNow) {
			ce := customerInfo{
				name:       customer.Name,
				expireDate: customer.ServiceEndDate,
				saleName:   customer.Business.Name,
			}
			expiresWithinAMonth = append(expiresWithinAMonth, ce)
		}
	}

	var emailBody string
	// 检查是否有维保即将过期的客户
	if len(expiresWithinAMonth) != 0 {
		var msg []string
		for _, c := range expiresWithinAMonth {
			m := fmt.Sprintf("客户: %s,&nbsp;&nbsp;&nbsp;&nbsp;维保截止日期: %s,&nbsp;&nbsp;&nbsp;&nbsp;销售: %s", c.name, c.expireDate.Format("2006-01-02"), c.saleName)
			msg = append(msg, m)
		}
		emailBody = fmt.Sprintf("维保即将过期的客户列表：</br>%s</br></br></br>", strings.Join(msg, "</br>"))
		global.TD27_LOG.Info(emailBody)
	}

	// 查询过期三个月内的维保客户
	var expireCustomers []CustomerModel.CustomerModel
	threeMonthsAgo := time.Now().Local().AddDate(0, -3, 0)
	if err := global.TD27_DB.Where("type = ? AND service_status = ? AND service_end_date >= ?", 2, 2, threeMonthsAgo).
		Preload("Business").Find(&expireCustomers).Error; err != nil {
		msg := fmt.Sprintf("查询数据失败: %s", err)
		global.TD27_LOG.Error(msg)
		return
	}

	if len(expireCustomers) != 0 {
		var msg []string

		for _, c := range expireCustomers {
			m := fmt.Sprintf("客户: %s,&nbsp;&nbsp;&nbsp;&nbsp;维保截止日期: %s,&nbsp;&nbsp;&nbsp;&nbsp;销售: %s", c.Name, c.ServiceEndDate.Format("2006-01-02"), c.Business.Name)
			msg = append(msg, m)
		}
		emailBody = fmt.Sprintf("%s </br> 维保已过期不足三个月的客户列表：</br>%s</br></br></br>", emailBody, strings.Join(msg, "</br>"))
	}

	if emailBody != "" {
		sendEmail(emailBody)
	}

	global.TD27_LOG.Info("定时任务 【检查维保状态】 执行完成.")
}

// deleteOldTempDir 删除三天前的块文件目录
func deleteOldTempDir() {
	global.TD27_LOG.Info("定时任务 【删除三天前的块文件目录】 开始执行.")
	dir := global.TD27_CONFIG.System.LocalStoreDir + "file/"
	// 构建 find 命令
	findCommand := fmt.Sprintf("find %s -mindepth 1 -maxdepth 1 -type d -ctime +3 -exec rm -rf {} \\;", dir)

	// 执行 find 命令
	cmd := exec.Command("sh", "-c", findCommand)
	_, err := cmd.CombinedOutput()
	if err != nil {
		msg := fmt.Sprintf("Error executing find command: %s", err)
		global.TD27_LOG.Error(msg)
		return
	}
	global.TD27_LOG.Info("定时任务 【删除三天前的块文件目录】 执行完成.")
}

// resetChunkUploadTable  重置chunk_upload_metadata表
func resetChunkUploadTable() {
	global.TD27_LOG.Info("定时任务 【重置chunk_upload_metadata表】 开始执行.")
	// 清空表中三天前数据
	now := time.Now().Add(-3 * 24 * time.Hour)
	global.TD27_DB.Where("created_at <= ?", now).Unscoped().Delete(&CustomerModel.ChunkUploadModel{})
	msg := fmt.Sprintf("删除chunk_upload_metadata表中三天前的数据")
	global.TD27_LOG.Info(msg)

	// 重置此表的自增ID为1
	sql := fmt.Sprintf("ALTER TABLE %s.chunk_upload_metadata AUTO_INCREMENT = 1", global.TD27_CONFIG.Mysql.Dbname)
	global.TD27_DB.Exec(sql)
	msg = fmt.Sprintf("修改chunk_upload_metadata表的自增ID为1.")
	global.TD27_LOG.Info(msg)
	global.TD27_LOG.Info("定时任务 【重置chunk_upload_metadata表】 执行完成.")
}

// checkLicenseStatus 检查license状态
func checkLicenseStatus() {
	global.TD27_LOG.Info("定时任务 【检查license状态】 开始执行.")
	var licenses []licenseRes.LicenseResult
	tenDays := time.Now().Add(10 * 24 * time.Hour)  // 获取当前日期加上十天的日期
	threeDays := time.Now().Add(3 * 24 * time.Hour) // 获取当前日期加上三天的日期

	err := global.TD27_DB.Model(&LicenseModel.LicenseModel{}).
		Select("license.*, customer.name,customer.type,customer_env.env").
		Joins("JOIN customer ON license.customer_id = customer.id").
		Joins("JOIN customer_env ON license.env_id = customer_env.id").
		Where("(active = ? AND customer.type = ? AND expired_date <= ?) OR (active = ? AND customer.type = ? AND expired_date <= ?)",
			1, 2, tenDays, 1, 1, threeDays).
		Find(&licenses).Error

	if err != nil {
		msg := fmt.Sprintf("查询数据失败: %s", err)
		global.TD27_LOG.Error(msg)
		return
	}

	var emailBody string
	msg := make(map[string][]string)
	// 遍历查询结果并逐一更新
	if len(licenses) != 0 {
		for _, l := range licenses {
			m := fmt.Sprintf("ID: %d，客户: %s，环境: %s，过期日期: %s", l.ID, l.Name, l.Env, strings.Split(l.ExpiredDate, "T")[0])
			if l.Type == 1 {
				msg["three"] = append(msg["three"], m)
			} else {
				msg["ten"] = append(msg["ten"], m)
			}
		}

		if len(msg["ten"]) != 0 {
			emailBody = fmt.Sprintf("【正式客户】</br>%s</br></br></br>", strings.Join(msg["ten"], "</br>"))
		}

		if len(msg["three"]) != 0 {
			emailBody = fmt.Sprintf("%s【POC客户】</br>%s</br></br></br>", emailBody, strings.Join(msg["three"], "</br>"))
		}

		emailBody = fmt.Sprintf("<span style=\"color: red;\">license即将过期通知</span></br></br>%s", emailBody)
		global.TD27_LOG.Info(emailBody)
		systemRec := strings.Split(global.TD27_CONFIG.SMTP.Rec, ",")
		err = utils.SendEmail("蜂巢售后相关指标告警", emailBody, systemRec)
		if err != nil {
			global.TD27_LOG.Error(fmt.Sprintf("蜂巢售后相关指标告警邮件发送失败，error: %s", err))
		} else {
			global.TD27_LOG.Info("蜂巢售后相关指标告警邮件发送成功.")
		}
	} else {
		global.TD27_LOG.Info("没有即将过期的license.")
	}

	global.TD27_LOG.Info("定时任务 【检查license状态】 执行完成.")
}

// updateLicenseStatus 更新license状态
func updateLicenseStatus() {
	global.TD27_LOG.Info("定时任务 【更新license状态】 开始执行.")
	var licenses []LicenseModel.LicenseModel
	var envInfo customerRes.CustomerEnvResult
	// 执行更新操作
	res := global.TD27_DB.Model(&LicenseModel.LicenseModel{}).
		Where("active = ? AND expired_date < ?", 1, time.Now()).
		Find(&licenses)

	if res.Error != nil {
		global.TD27_LOG.Error(fmt.Sprintf("查询已过期的license失败，error：%s", res.Error))
	} else {
		var msg []string
		// 遍历查询结果并逐一更新
		for _, l := range licenses {
			global.TD27_DB.Model(&CustomerModel.CustomerEnvModel{}).
				Select("customer_env.env, customer.name").
				Joins("JOIN customer ON customer_env.customer_id = customer.id").
				Where("customer_env.id = ?", l.EnvID).
				Find(&envInfo)

			m := fmt.Sprintf("ID: %d，客户: %s，环境: %s，过期日期: %s", l.ID, envInfo.Name, envInfo.Env, l.ExpiredDate.Format("2006-01-02"))
			msg = append(msg, m)
			l.Active = 2
			result := global.TD27_DB.Save(&l)
			if result.Error != nil {
				global.TD27_LOG.Error(fmt.Sprintf("更新license：%d 失败，error：%s", l.ID, result.Error))
			} else {
				global.TD27_LOG.Info(fmt.Sprintf("更新license：%d 成功.", l.ID))
			}
		}

		if len(msg) != 0 {
			emailBody := fmt.Sprintf("license最新过期列表：</br>%s</br></br></br>", strings.Join(msg, "</br>"))
			global.TD27_LOG.Info(emailBody)
			systemRec := strings.Split(global.TD27_CONFIG.SMTP.Rec, ",")
			err := utils.SendEmail("蜂巢售后相关指标告警", emailBody, systemRec)
			if err != nil {
				global.TD27_LOG.Error(fmt.Sprintf("蜂巢售后相关指标告警邮件发送失败，error: %s", err))
			} else {
				global.TD27_LOG.Info("蜂巢售后相关指标告警邮件发送成功.")
			}
		}
	}
	global.TD27_LOG.Info("定时任务 【更新license状态】 执行完成.")
}

// addCron 添加一个定时任务
func addCron(spec string, cmd func()) {
	pc := reflect.ValueOf(cmd).Pointer()
	funcName := runtime.FuncForPC(pc).Name()

	id, err := global.TD27_CRON.AddFunc(spec, cmd)
	if err != nil {
		global.TD27_LOG.Info(
			fmt.Sprintf("Add Cron Failure,spec: %s,cron: %s,error: %s", spec, funcName, err))
	} else {
		global.TD27_LOG.Info(fmt.Sprintf("Add Crontab Success; ID: %v,task: %s", id, funcName))
	}
}

func StartCrontab() {
	// 更新维保状态，每天凌晨1点执行
	addCron("00 1 * * *", UpdateServiceStatus)
	// 检查维保有效期不足一个月和过期不足三个月的客户列表，每周一早上8点执行
	addCron("00 8 * * 1", checkServiceStatus)
	// 删除上传文件产生的三天前的块文件，每天凌晨3点执行
	addCron("00 3 * * *", deleteOldTempDir)
	// 重置 chunk_upload_metadata 表的自增ID，防止增长过大，每个月1号凌晨三点执行
	addCron("00 3 1 * *", resetChunkUploadTable)
	// 检查license有效期不足10天的正式客户和不足3天的POC客户，每天早上8点执行
	addCron("00 8 * * *", checkLicenseStatus)
	// 更新license的状态，每天凌晨1点执行
	addCron("00 1 * * *", updateLicenseStatus)
	global.TD27_CRON.Start()
}
